#include "libcomm.h"

#define CHECK_BUFFER_OVERLAP(ptr)	MYLIB_ASSERT((ptr<this->get() || ptr>this->get()+this->size()) && "memory overlap!");

// strdup has bugs in windows linked in different CRT.
char* Buffer::strdup(const char* src)
{
	if(NULL == src)
		return NULL;
	int length = ::strlen(src);
	char *dest = (char*)Buffer::calloc(length + 1,sizeof(char));
	if(NULL == dest)
		return NULL;
	::memcpy(dest,src,length);
	return dest;
}

void* Buffer::malloc(size_t size)
{
	return ::malloc(size);
}

void* Buffer::calloc(size_t num, size_t size)
{
	return ::calloc(num,size);
}

void* Buffer::realloc(void* ptr, size_t size)
{
	return ::realloc(ptr,size);
}

void Buffer::free(void* ptr)
{
	::free(ptr);
}


Buffer::Buffer(size_t size):m_buffer(NULL),m_size(0)
{
	if(size > 0)
	{
		m_size = size;
		m_buffer = (char*)Buffer::calloc(m_size,1);
		MYLIB_ASSERT_NOTNULL(m_buffer);
	}
}

Buffer::Buffer(const void* ptr, size_t size):m_buffer(NULL),m_size(0)
{
	if(NULL != ptr && size > 0)
	{
		m_size = size;
		m_buffer = (char*)Buffer::malloc(m_size);
		MYLIB_ASSERT_NOTNULL(m_buffer);
		::memcpy(m_buffer,ptr,m_size);
	}
}

Buffer::Buffer(const char* src):m_buffer(NULL),m_size(0)
{
	if(NULL != src)
	{
		m_size = ::strlen(src) + 1;
		m_buffer = (char*)Buffer::calloc(m_size,sizeof(char));
		MYLIB_ASSERT_NOTNULL(m_buffer);
		::memcpy(m_buffer,src,m_size-1);
	}
}

Buffer::Buffer(const Buffer& rhs):m_buffer(NULL),m_size(0)
{
	const char* mem = rhs;
	size_t size = rhs.size();
	if(NULL != mem && size > 0)
	{
		m_size = size;
		m_buffer = (char*)Buffer::malloc(m_size);
		MYLIB_ASSERT_NOTNULL(m_buffer);
		::memcpy(m_buffer,mem,m_size);
	}
}

Buffer& Buffer::operator=(const Buffer& rhs)
{
	const char* mem = rhs;
	size_t size = rhs.size();
	if(NULL != mem && size > 0 && rhs.get() != m_buffer) // may be self = self.
	{
		this->release();
		m_size = size;
		m_buffer = (char*)Buffer::malloc(m_size);
		MYLIB_ASSERT_NOTNULL(m_buffer);
		::memcpy(m_buffer,mem,m_size);
	}
	return *this;
}

Buffer::~Buffer(void)
{
	this->release();
}

void Buffer::release()
{
	if(NULL != m_buffer)
	{
		Buffer::free(m_buffer);
		m_buffer = NULL;
		m_size = 0;
	}
}

Buffer::operator char*()
{
	return this->get();
}

Buffer::operator const char*() const
{
	return this->get();
}

char* Buffer::get()
{
	return m_buffer;
}

const char* Buffer::get() const
{
	return m_buffer;
}

size_t Buffer::size() const
{
	return m_size;
}

Buffer& Buffer::memset(int val)
{
	::memset(m_buffer,val,m_size);
	return *this;
}

Buffer& Buffer::resize(size_t size)
{
	if(size > m_size)
	{
		m_buffer = (char*)Buffer::realloc(m_buffer, size);
		MYLIB_ASSERT_NOTNULL(m_buffer);
		::memset(m_buffer + m_size, 0, size - m_size);
	}
	else
	{
		::memset(m_buffer + size, 0, m_size - size);
	}
	m_size = size;
	return *this;
}

Buffer& Buffer::consume(size_t size)
{
	MYLIB_ASSERT(size >= 0 && size <= m_size);
	if(size == m_size)
		::memset(m_buffer, 0, m_size);
	else
		::memmove(m_buffer, m_buffer + size , m_size-size);
	m_size -= size;
	return *this;
}

Buffer& Buffer::append(const void* ptr, int size)
{
	if (NULL != ptr && 0 < size)
	{
		size_t old_size = this->size();
		CHECK_BUFFER_OVERLAP(ptr);
		this->resize(old_size + size);
		memcpy(m_buffer + old_size, ptr, size);
	}
	return *this;
}

Buffer& Buffer::append(const Buffer& rhs)
{
	return append(rhs.get(),rhs.size());
}


////////////////////////////////////////////////////////////////////////// StringList

typedef std::vector<String> InnerStringVector;
#define STRINGLISTINST ((InnerStringVector*)m_list)
#define STRINGLISTINSTCOPY(rhs)	(*((InnerStringVector*)m_list) = *((InnerStringVector*)rhs.m_list))

StringList::StringList():m_list(NULL)
{
	m_list = new InnerStringVector();
	MYLIB_ASSERT_NOTNULL(m_list);
}

StringList::StringList(const StringList& rhs):m_list(NULL)
{
	m_list = new InnerStringVector();
	MYLIB_ASSERT_NOTNULL(m_list);
	STRINGLISTINSTCOPY(rhs);
}

StringList& StringList::operator=(const StringList& rhs)
{
	if(m_list != rhs.m_list)
	{
		STRINGLISTINSTCOPY(rhs);
	}
	return *this;
}

StringList::~StringList()
{
	if(NULL != m_list)
	{
		delete STRINGLISTINST;
		m_list = NULL;
	}
}

int StringList::count() const
{
	return STRINGLISTINST->size();
}

String& StringList::get(int index)
{
	MYLIB_ASSERT(index>=0 && index<count());
	return STRINGLISTINST->at(index);
}

const String& StringList::get(int index) const
{
	MYLIB_ASSERT(index>=0 && index<count());
	return STRINGLISTINST->at(index);
}

String& StringList::operator[](int index)
{
	return get(index);
}

const String& StringList::operator[](int index) const
{
	return get(index);
}

StringList& StringList::append(const String& inst)
{
	STRINGLISTINST->push_back(inst);
	return *this;
}

StringList& StringList::insert(int index, const String& inst)
{		
	MYLIB_ASSERT(index>=0 && index<=count());
	InnerStringVector::iterator itor = STRINGLISTINST->begin();
	for (int i=0;i<index;i++)
		itor++;
	STRINGLISTINST->insert(itor,inst);
	return *this;
}	

StringList& StringList::remove(int index)
{
	MYLIB_ASSERT(index>=0 && index<count());
	InnerStringVector::iterator itor = STRINGLISTINST->begin();
	for (int i=0;i<index;i++)
		itor++;
	STRINGLISTINST->erase(itor);
	return *this;
}

StringList& StringList::clear()
{
	STRINGLISTINST->clear();
	return *this;
}

StringList& StringList::operator<<(const String& inst)
{
	return append(inst);
}

String StringList::join(const char* seperators) const
{
	String str;
	int count = this->count();
	for (int i=0;i<count;i++)
	{
		const String& item = this->get(i);
		if(i != 0)
			str << seperators;
		str << item;
	}
	return str;
}


////////////////////////////////////////////////////////////////////////// String
String String::Empty = "";

static bool _IsEmptyChar(char c)
{
	char empty[] = " \t\n\r";
	char* pos = empty;
	while(0 != pos[0])
	{
		if(pos[0] == c)
			return true;
		++pos;
	}
	return false;
}

String::String(int length):Buffer(length+1)
{
}

String::String(const char* src):Buffer(src)
{
}

String::String(const String& rhs):Buffer(rhs.get())
{

}

char& String::operator[](int index)
{
	char* buffer = this->get();
	int size = this->size();
	MYLIB_ASSERT(index >= 0 && index < size && NULL != buffer);
	return buffer[index];
}

const char& String::operator[](int index) const
{
	const char* buffer = this->get();
	int size = this->size();
	MYLIB_ASSERT(index >= 0 && index < size && NULL != buffer);
	return buffer[index];
}

bool String::null() const
{
	const char* buffer = this->get();
	int size = this->size();
	if(NULL == buffer || 0 == size)
		return true;
	return false;
}

bool String::empty() const
{
	if(!this->null())
	{
		int length = this->length();
		const char* cursor = this->get();
		for (int i=0;i<length;i++)
		{
			if(_IsEmptyChar(cursor[i]))
				continue;
			return false;
		}
	}
	return true;
}

int String::length() const
{
	int length = 0;
	int size = this->size();
	if(!this->null())
	{
		length = ::strlen(this->get());
		MYLIB_ASSERT(length<size); // not end by '\0'.
	}
	return length;
}

bool String::equal(const char* src, bool ignorecase) const
{
	int ret = -1;
	if(this->null() || NULL==src)
	{
		return (this->null() && NULL==src);
	}

	if(ignorecase)
	{
#ifdef COMM_MSVC
		ret = ::_stricmp(this->get(),src);
#else
		ret = ::strcasecmp(this->get(),src);
#endif
	}
	else
	{
		ret = ::strcmp(this->get(),src);
	}

	return (0==ret);
}

String& String::append(const char* src)
{
	if(NULL != src)
	{
		int length = ::strlen(src);
		size_t new_size = this->length() + length + 1;
		CHECK_BUFFER_OVERLAP(src);
		this->resize(new_size);
		this->strcat(src);
	}
	return *this;
}

String& String::operator+=(const char* src)
{
	return this->append(src);
}

String& String::operator<<(const char* src)
{
	return this->append(src);
}

String String::operator+(const char* src) const
{
	String dest(this->get());
	dest += src;
	return dest;
}

bool String::operator==(const char* src) const
{
	return this->equal(src);
}

bool String::operator!=(const char* src) const
{
	return !this->equal(src);
}

bool String::operator==(const String& src) const
{
	return this->equal(src);
}

bool String::operator!=(const String& src) const
{
	return !this->equal(src);
}

int String::toint() const
{
	if(this->null())
		return 0;
	return atoi(this->get());
}

long String::tolong() const
{
	if(this->null())
		return 0;
	return atol(this->get());
}

double String::todouble() const
{
	if(this->null())
		return 0.0f;
	return atof(this->get());
}

String& String::tolower()
{
	if(!this->null())
	{
		char* pos = this->get();
		while(pos[0] != 0)
		{
			pos[0] = ::tolower(pos[0]);
			++pos;
		}
	}
	return *this;
}

String& String::toupper()
{
	if(!this->null())
	{
		char* pos = this->get();
		while(pos[0] != 0)
		{
			pos[0] = ::toupper(pos[0]);
			++pos;
		}
	}
	return *this;
}

String& String::reverse()
{
	if(!this->null())
	{
		char* s = this->get();
		char* h = s;  
		char* t = s;
		char ch;
		while(*t++){};
		t--;    
		t--;   
		while(h < t)
		{
			ch = *h;
			*h++ = *t;  
			*t-- = ch; 
		}
	}
	return *this;
}

String& String::trimleft()
{
	if(!this->null())
	{
		String tmp = this->get();
		char* cursor = tmp;
		int length = tmp.length();
		int i;
		for (i=0;i<length;i++)
		{
			if(_IsEmptyChar(cursor[i]))
			{
				continue;
			}
			break;
		}
		if(i != 0)
			*this = cursor + i;
	}
	return *this;
}

String& String::trimright()
{
	if(!this->null())
	{
		String tmp = this->get();
		char* cursor = tmp;
		int length = tmp.length();
		int i;
		for(i=length-1;i>=0;i--)
		{
			if(_IsEmptyChar(cursor[i]))
			{
				cursor[i] = 0;
				continue;
			}
			break;
		}
		if(i != length-1)
			*this = cursor;
	}
	return *this;
}

String& String::trim()
{
	return this->trimleft().trimright();
}

String& String::replace(const char* substr, const char* newstr, bool replaceall)
{
	if(!this->null() && NULL != substr && NULL != newstr)
	{
		String tmp;
		char* start = this->get();
		char* pos = NULL;
		int substr_len = strlen(substr);
		while(NULL != (pos = strstr(start,substr)))
		{
			pos[0] = 0;
			tmp += start;
			tmp += newstr;
			start = pos + substr_len;
			if(!replaceall)
				break;
		}
		tmp += start;
		*this = tmp;
	}
	return *this;
}

String& String::remove(const char* substr, bool removeall)
{
	return this->replace(substr,"",removeall);
}

bool String::find(const char* str) const
{
	if(this->null() || NULL == str)
		return false;
	return (NULL != strstr(this->get(),str));
}

bool String::startwith(const char* str) const
{
	if(this->null() || NULL == str)
		return false;
	return (strstr(this->get(),str) == this->get());
}

bool String::endwith(const char* str) const
{
	if(this->null() || NULL == str)
		return false;
	String tmp_src = this->get();
	String tmp_str = str;
	tmp_src.reverse();
	tmp_str.reverse();
	return tmp_src.startwith(tmp_str);
}

StringList String::split(const char* seperators) const
{
	StringList list;
	if (!this->null() && NULL != seperators)
	{
		String tmp = this->get();
		char* pToken = NULL;
#ifdef COMM_MSVC
		pToken = ::strtok(tmp, seperators);
		while (NULL != pToken)
		{
			list.append(pToken);
			pToken = strtok(NULL, seperators);
		}
#else
		char* pSave = NULL;
		pToken = ::strtok_r(tmp, seperators, &pSave);
		while (NULL != pToken)
		{
			list.append(pToken);
			pToken = ::strtok_r(NULL, seperators, &pSave);
		}
#endif
	}
	return list;
}


String& String::strcpy(const char* src)
{
	if(!this->null() && NULL != src)
	{
		char* buffer = this->get();
		int size = this->size();
		CHECK_BUFFER_OVERLAP(src);
		::strncpy(buffer,src,size-1);
		buffer[size-1] = 0;
	}
	return *this;
}

String& String::strcat(const char* src)
{
	if(!this->null() && NULL != src)
	{
		char* buffer = this->get();
		int size = this->size();
		int length = this->length();
		CHECK_BUFFER_OVERLAP(src);
		::strncpy(buffer+length,src,size-1-length);
		buffer[size-1] = 0;
	}
	return *this;
}

String& String::vsprintf(const char* format, va_list args)
{
	if(!this->null() && NULL != format)
	{
		char* buffer = this->get();
		int size = this->size();
		CHECK_BUFFER_OVERLAP(format);
		::vsnprintf(buffer, size-1, format, args);
		buffer[size-1] = 0;
	}
	return *this;
}

String& String::sprintf(const char* format, ...)
{
	va_list args;
	va_start(args, format);
	this->vsprintf(format, args);
	va_end(args);
	return *this;
}

////////////////////////////////////////////////////////////////////////// Static 

bool String::equal(const char* src, const char* str, bool ignorecase)
{
	return String(src).equal(str,ignorecase);
}

String String::join(const char* src, const char* str)
{
	return String(src).append(str);
}

String String::tolower(const char* src)
{
	return String(src).tolower();
}

String String::toupper(const char* src)
{
	return String(src).toupper();
}

String String::reverse(const char* src)
{
	return String(src).reverse();
}

String String::trimleft(const char* src)
{
	return String(src).trimleft();
}

String String::trimright(const char* src)
{
	return String(src).trimright();
}

String String::trim(const char* src)
{
	return String(src).trim();
}

bool String::find(const char* src, const char* str)
{
	return String(src).find(str);
}

bool String::startwith(const char* src, const char* str)
{
	return String(src).startwith(str);
}

bool String::endwith(const char* src, const char* str)
{
	return String(src).endwith(str);
}

StringList String::split(const char* src, const char* seperators)
{
	return String(src).split(seperators);
}


String String::format(const char* format, ...)
{
	String dest(COMM_STRING_DEFAULT_LENGTH);
	va_list args;
	va_start(args, format);
	dest.vsprintf(format, args);
	va_end(args);
	return dest;
}

String String::format(int size, const char* format, ...)
{
	String dest(size);
	va_list args;
	va_start(args, format);
	dest.vsprintf(format, args);
	va_end(args);
	return dest;
}
